package hou.just4fun.SeekGirlFriend.work;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import hou.just4fun.SeekGirlFriend.model.Couple;
import hou.just4fun.SeekGirlFriend.model.Gender;
import hou.just4fun.SeekGirlFriend.model.Person;

/**
 * @author houweitao
 * @date 2016年5月13日下午2:59:46
 * @TODO 配对之后，可以选择去追还是不追。追求成功？ 喜欢的情况下：1：对方有配偶，你的得分比对方配偶高 2：对方无配偶，成功
 * @TODO 添加：每个人不是认识所有的人啊！越接近现实生活越好..2016年05月13日18:09:59
 */

public class MakeCouples {
	private Map<String, Person> menMap;
	private Map<String, Person> womenMap;
	private Map<String, Couple> coupleMap;
	private static final int friendCircle = 50;

	public static void main(String[] args) {
		MakeCouples makeCouple = new MakeCouples();
		makeCouple.init();
	}

	void init() {
		menMap = new HashMap<>();
		womenMap = new HashMap<>();
		coupleMap = new HashMap<>();
		List<Person> menList = new ArrayList<>();
		List<Person> womenList = new ArrayList<>();
		giveBirth2Person(menList, womenList);

		Person perfectGirl = new Person(Gender.female, womenList.size());
		perfectGirl.perfect();

		buildLoverMap(menList, womenList);

		// for (Person man : menList) {
		// Map<Person, Integer> map = man.getLoverScoreMap();
		// System.out.println(man + ": " + map.size());
		// showMap(map);
		// break;
		// }

		// appointment(200);
		appointmentRandom(500);
		showCoupleStatus();
		myFriendMarriageRage();
		scoreAboutCouple();
	}

	private void scoreAboutCouple() {
		int singleMan = 0;
		int happyMan = 0;
		double aveSM = 0;
		double aveHM = 0;

		int singleWoman = 0;
		int happyWoman = 0;
		double aveSW = 0;
		double aveHW = 0;

		for (Entry<String, Person> entry : menMap.entrySet()) {
			Person man = entry.getValue();
			if (man.getLover() == null) {
				singleMan++;
				aveSM = aveSM + man.getSelfScore();
			} else {
				happyMan++;
				aveHM = aveHM + man.getSelfScore();
			}
		}
		aveSM = aveSM / singleMan;
		aveHM = aveHM / happyMan;

		for (Entry<String, Person> entry : womenMap.entrySet()) {
			Person woman = entry.getValue();
			if (woman.getLover() == null) {
				singleWoman++;
				aveSW = aveSW + woman.getSelfScore();
			} else {
				happyWoman++;
				aveHW = aveHW + woman.getSelfScore();
			}
		}
		aveSW = aveSW / singleWoman;
		aveHW = aveHW / happyWoman;

		System.out.println("结婚的男人数目:" + happyMan + " 平均分：" + aveHM);
		System.out.println("单身的男人数目:" + singleMan + " 平均分：" + aveSM);
		System.out.println("结婚的女人数目:" + happyWoman + " 平均分：" + aveHW);
		System.out.println("单身的女人数目:" + singleWoman + " 平均分：" + aveSW);

	}

	void myFriendMarriageRage() {
		for (Entry<String, Person> entry : menMap.entrySet()) {
			Person man = entry.getValue();
			int no = 0;
			int yes = 0;
			int all = 0;
			for (String str : man.getAcknowledge()) {
				Person woman = womenMap.get(str);
				if (woman.getLover() == null)
					no++;
				else
					yes++;
				all++;
			}
			String str = "我是" + man.getName() + ", 我的基本得分是：" + man.getSelfScore() + ",";
			if (man.getLover() == null)
				str = str + "我没有女朋友";
			else
				str = str + "我有女朋友";

			str = str + "，我认识" + all + "个异性朋友，其中有 " + no + " 个还是单身。";
			str = str + "还有" + man.getLoverScoreMap().size() + "潜在对象";

			System.out.println(
					str + ";" + man.getName() + "(" + yes + "/" + all + ")" + (double) ((double) yes / (double) all));
		}
	}

	private void showCoupleStatus() {
		int stableNum = 0;
		for (Entry<String, Couple> entry : coupleMap.entrySet()) {
			String stable = "";
			if (isStable(entry.getValue())) {
				stable = "稳定婚姻：";
				stableNum++;
			} else {
				stable = "不稳定婚姻：";
			}
			System.out.println(stable + entry.getValue());
		}
		System.out.println(coupleMap.size() + ",稳定婚姻数目：" + stableNum);
	}

	boolean isStable(Couple couple) {
		Person man = couple.getHusband();
		Person woman = couple.getWife();

		List<Map.Entry<String, Integer>> manLover = man.getSortedLovers();
		List<Map.Entry<String, Integer>> womanLover = woman.getSortedLovers();

		for (Entry<String, Integer> entry : manLover) {
			if (entry.getKey().equals(woman.getName()))
				break;
			if (womenMap.get(entry.getKey()).getLover() != null) {
				return false;
			}
		}
		for (Entry<String, Integer> entry : womanLover) {
			if (entry.getKey().equals(man.getName()))
				break;
			if (menMap.get(entry.getKey()).getLover() != null)
				return false;
		}

		return true;
	}

	private void appointment(int time) {
		for (int i = 0; i < time; i++) {
			for (Entry<String, Person> entry : menMap.entrySet()) {
				Person man = entry.getValue();
				// if (man.getLover() != null) {
				if (true) {
					// TODO 下一步，让男人根据自己最心爱的女人去求偶。而不是无头苍蝇 2016年05月13日17:37:12
					// int target = (int) (womenMap.size() * Math.random());
					// Person woman = womenMap.get("woman-" + target);

					boolean flag = false;

					// this
					while (!flag) {
						// System.out.println(flag);
						List<Map.Entry<String, Integer>> loverList = man.getSortedLovers();
						// System.out.println(loverList.size());
						if (loverList != null && loverList.size() > 0) {
							Person woman = womenMap.get(loverList.get(0).getKey());
							if (fallInLove(man, woman) && fallInLove(woman, man)) {
								Person womanHusband = woman.getLover();
								int husbandScore = womanHusband == null ? 0
										: woman.getLoverScoreMap().get(womanHusband);
								int curScore = woman.getLoverScoreMap().get(man);

								if (curScore > husbandScore) {
									woman.setLover(man);
									man.setLover(woman);
									if (womanHusband != null) {
										womanHusband.setLover(null);
										coupleMap.remove(womanHusband.getName());
										// woman.getLoverScoreMap().remove(womanHusband);
										womanHusband.getLoverScoreMap().remove(woman);
									}

									System.out.println("成了");
									coupleMap.put(man.getName(), new Couple(man, woman));
									flag = true;
								} else {
									man.getLoverScoreMap().remove(woman.getName());
									// woman.getLoverScoreMap().remove(man);
								}
							} else {
								man.getLoverScoreMap().remove(woman.getName());
								// woman.getLoverScoreMap().remove(man);
							}
						} else
							break;
					}
				}
			}

			System.out.println("第 " + i + " 次约会");
			showCoupleStatus();
			System.out.println("=========");
		}

	}

	private void appointmentRandom(int time) {

		for (int i = 0; i < time; i++) {
			for (Entry<String, Person> entry : menMap.entrySet()) {
				Person man = entry.getValue();
				boolean flag = false;
				if (man.getLover() == null) {
					int fav = 0;
					while (!flag) {
						if (man.getLoverScoreMap().size() < 1)
							break;
						// System.out.println(man.getLoverScoreMap().size());

						int target = (int) (womenMap.size() * Math.random());
						Person woman = womenMap.get("woman-" + target);

						woman = womenMap.get(man.getAcknowledge().get(fav++));

						if (acknowledge(man, woman) && acknowledge(woman, man) && fallInLove(man, woman)
								&& fallInLove(woman, man)) {
							Person womanHusband = woman.getLover();
							int husbandScore = womanHusband == null ? 0
									: woman.getLoverScoreMap().get(womanHusband.getName());

							int curScore = 0;

							if (woman.getLoverScoreMap().get(man.getName()) != null)
								curScore = woman.getLoverScoreMap().get(man.getName());

							if (curScore > husbandScore) {
								woman.setLover(man);
								man.setLover(woman);
								if (womanHusband != null) {
									womanHusband.setLover(null);
									coupleMap.remove(womanHusband.getName());
									woman.getLoverScoreMap().remove(womanHusband.getName());
									womanHusband.getLoverScoreMap().remove(woman.getName());
									woman.getAcknowledge().remove(womanHusband.getName());
									womanHusband.getAcknowledge().remove(woman.getName());
								}

								System.out.println("成了");
								flag = true;
								coupleMap.put(man.getName(), new Couple(man, woman));
							} else {
								man.getLoverScoreMap().remove(woman.getName());
								// woman.getLoverScoreMap().remove(man.getName());
							}
						} else {
							man.getLoverScoreMap().remove(woman.getName());
							// woman.getLoverScoreMap().remove(man.getName());
						}
					}
				}
			}

			System.out.println("第 " + i + " 次约会");

			showCoupleStatus();
			System.out.println("=========");

		}

	}

	private boolean acknowledge(Person man, Person woman) {
		if (man.getAcknowledge().contains(woman.getName()))
			return true;
		else
			return false;
	}

	void buildLoverMap(List<Person> men, List<Person> women) {
		for (Person man : men) {
			int loverNum = man.getLoversNum();
			int count = 0;
			// 以后可以优化一下。如果样本数目太多的话效率是问题
			Collections.shuffle(women);
			// for (int i = 0; i < women.size(); i++) {
			for (int i = 0; i < friendCircle; i++) {
				Person woman = women.get(i);

				if (!woman.getAcknowledge().contains(man.getName()))
					woman.getAcknowledge().add(man.getName());
				if (!man.getAcknowledge().contains(woman.getName()))
					man.getAcknowledge().add(woman.getName());

				if (count < loverNum) {
					if (fallInLove(man, woman)) {
						count++;
						man.getLoverScoreMap().put(woman.getName(), woman.getSelfScore() + randomInt());
						woman.getLoverScoreMap().put(man.getName(), man.getSelfScore() + randomInt());
					} else {
						man.getLoverScoreMap().put(woman.getName(), woman.getSelfScore());
						woman.getLoverScoreMap().put(man.getName(), man.getSelfScore());
					}
				} else {
					// 后来大家年纪大了，只看重对方的条件。相亲
					man.getLoverScoreMap().put(woman.getName(), woman.getSelfScore());
					woman.getLoverScoreMap().put(man.getName(), man.getSelfScore());

				}

				// System.out.println(man.getName() + ": " +
				// man.getLoverScoreMap().size());
			}
		}

		for (Person woman : women) {
			int loverNum = woman.getLoversNum();
			int count = 0;
			// 以后可以优化一下。如果样本数目太多的话效率是问题
			Collections.shuffle(men);
			// for (int i = 0; i < men.size(); i++) {
			for (int i = 0; i < friendCircle; i++) {
				Person man = men.get(i);

				if (!woman.getAcknowledge().contains(man.getName()))
					woman.getAcknowledge().add(man.getName());
				if (!man.getAcknowledge().contains(woman.getName()))
					man.getAcknowledge().add(woman.getName());

				if (count < loverNum) {
					if (fallInLove(woman, man)) {
						count++;
						woman.getLoverScoreMap().put(man.getName(), man.getSelfScore() + randomInt());
						man.getLoverScoreMap().put(woman.getName(), woman.getSelfScore() + randomInt());
					} else {
						woman.getLoverScoreMap().put(man.getName(), man.getSelfScore());
						man.getLoverScoreMap().put(woman.getName(), woman.getSelfScore());

					}
				} else {
					// 后来大家年纪大了，只看重对方的条件。相亲
					woman.getLoverScoreMap().put(man.getName(), man.getSelfScore());
					man.getLoverScoreMap().put(woman.getName(), woman.getSelfScore());

				}
			}
		}
	}

	// 一开始的时候大家重感情，有感情分
	private int randomInt() {
		return (int) (20 * Math.random()) + 5;
	}

	void giveBirth2Person(List<Person> menList, List<Person> womenList) {
		int menNum = 0;
		int womenNum = 0;
		for (int i = 0; i < 200; i++) {
			if (Math.random() > 0.48) {
				Person man = new Person(Gender.male, menNum++);
				menList.add(man);
				menMap.put(man.getName(), man);
			} else {
				Person woman = new Person(Gender.female, womenNum++);
				womenList.add(woman);
				womenMap.put(woman.getName(), woman);
			}
		}

		System.out.println(menList.size());
		System.out.println(womenList.size());
	}

	// TODO 二人相爱的策略是否可以调优 2016年05月13日17:38:09
	boolean fallInLove(Person one, Person two) {
		if (one.getGender() == two.getGender())
			return false;
		else {
			int score = 0;
			int education = diffTooMuch(one.getEducation(), two.getEducation()) ? 0 : 1;
			int wealth = diffTooMuch(one.getWealth(), two.getWealth()) ? 0 : 1;
			int handsome = diffTooMuch(one.getHandsome(), two.getHandsome()) ? 0 : 1;
			int love = (int) (3 * Math.random());
			score = education + wealth + handsome + love;

			if (score >= 3)
				return true;
			else
				return false;
		}
	}

	boolean diffTooMuch(int a, int b) {
		if (a == 0 && b == 0)
			return false;
		else if (a == 0 || b == 0) {
			if (Math.abs(a - b) < 2)
				return false;
			else
				return true;
		} else {
			if (a - b >= 5)// 大家都喜欢比自己好的。如果比自己差太多就不可以了
				return false;
			else
				return true;
		}
	}

	void showMap(Map<Person, Integer> map) {
		int i = 0;
		for (Entry<Person, Integer> entry : map.entrySet()) {
			System.out.println(
					"次序" + i++ + " 得分:" + entry.getValue() + "," + entry.getKey().getName() + ": " + entry.getKey());
		}
	}
}
